# CCNCore::Scripting.pm
# Copyright (C) 2006  Stephane Alnet
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 

#
# For more information visit http://carrierclass.net/
#

use strict; use warnings;

package CCNCore::Scripting;
use CCNCore::Home;
use CCN::Scripting;
use CCN::Text;
use Carp;

use Exporter::Lite;
our @EXPORT = qw( &IF_CHANGED &CAT &RCLOCAL &COMMIT_MODULE );

sub CRONTAB($)
{
    my $content = shift;
    return "INTERNAL ERROR: CRONTAB($content) is not quote-safe\n" if $content =~ /'/;
    CCN::Scripting::exec_command CCNCore::Home::manager."/bin/provision/crontab-addentry.sh '$content'";
    return '';
}

sub PREPARE($)
{
    return CCNCore::Home::config.'/local/content'.$_[0];
}

# ------------ commit.pl ------------

sub commit_start_file($$$)
{
    my ($commit_template,$file,$log) = @_;
    open(COMMIT_PL,'>',$file) or croak "ERROR: Could not create $file: $!";
    print COMMIT_PL template_text(
        content_of($commit_template),
        {
            'LOG'   => $log,
        });
}

sub commit_start($)
{
    my ($commit_template) = @_;
    commit_start_file($commit_template,CCNCore::Home::config.'/local/bin/commit.pl','predb');
}

sub commit_end()
{
    print COMMIT_PL "\nrun_them();\n";
    print COMMIT_PL qq(print "SUCCESS: Commit successful\\n";\nexit 0;\n);
    close COMMIT_PL;
}

sub COMMIT_MODULE($)
{
    my $module = shift;
    print COMMIT_PL <<PERL;
do {
    print STDERR "CCN-INFO: Attempting to commit module ${module}.\\n";
    use ${module};
    my \$a = new ${module} (\$local) or die "Could not create ${module}";
    \$a->commit(\$c,\$r);
    \$a->finish() or die "CCN-ERROR: Module ${module} did not commit properly";
    print STDERR "CCN-INFO: Module ${module} committed.\n";
};
PERL
}

# CAT $filename $content
sub CAT($$)
{
    my ($file,$content) = @_;
    $file = $file;
    return "INTERNAL ERROR: CAT(@_)\n"
        unless $file =~ m{^/};

    print COMMIT_PL "commit_file(q($file));\n"
        or croak "INTERNAL ERROR: print: $!";

    # Generate the file in the private spool
    $file = PREPARE $file;
    CCN::Scripting::exec_command(qq(mkdir -p `dirname '$file'`));

    return print_to($file,$content);
}

sub _COMMIT($$)
{
    my ($file,$sub) = @_;
    
    print COMMIT_PL "commit(q($file), sub { $sub } );\n";
}

# IF_CHANGED $filename => $command
sub IF_CHANGED($$)
{
    # croak 'INTERNAL ERROR: IF_CHANGED force_manager' if $force_manager;
    my ($file,$command) = @_;
    $file = $file;
    croak "INTERNAL ERROR: IF_CHANGED(@_)" unless defined $file and defined $command;
    if($file eq '')
    {
        print COMMIT_PL "run_once q($command);\n";
        return;
    }
    if($command eq '')
    {
        return;
    }
    # Both file and command are provided.
    _COMMIT($file,"run_once q($command)");
}

# MONITOR $filename
sub MONITOR($)
{
    my ($file) = @_;
    $file = $file;
    croak "INTERNAL ERROR: MONITOR(@_)" unless $file =~ m{^/};

    print COMMIT_PL "run_once q(!commit_file('$file'));\n";
}

# -------------- Rclocal -----------

sub rclocal_start()
{
    open(RCLOCAL_SH,'>',CCNCore::Home::config.'/local/bin/rc.local')
        or croak "ERROR: Could not create ".CCNCore::Home::config."/local/bin/rc.local: $!";
    print RCLOCAL_SH copyright("#!/bin/sh\n# rc.local\n");
}

sub rclocal_end()
{
    close RCLOCAL_SH;    
}

sub RCLOCAL($)
{
    my $cmd = shift;
    print RCLOCAL_SH "$cmd\n";
}

# --------------- Services ---------------

our $deferred_file = CCNCore::Home::config.'/local/bin/deferred.sh';

sub deferred_start()
{
    open(DEFERRED_SH,'>',$deferred_file)
        or croak "ERROR: Could not create $deferred_file: $!";
    print DEFERRED_SH copyright("#!/bin/sh\n# $deferred_file\nexport PATH=/usr/sbin:/usr/bin:/sbin:/bin\n\n");
}

sub deferred_end()
{
    # Move ourselves out of the way
    print DEFERRED_SH qq(/bin/mv '$deferred_file' '$deferred_file.back'\n);
    close DEFERRED_SH;
    use CCNCore::IPC::Spool;
    my $spool = new CCNCore::IPC::Spool;
    $spool->spool_request("run-deferred");
}

sub DEFER($)
{
    my $cmd = shift;
    print DEFERRED_SH "$cmd\n";
}

# ---- Start/end for all files ----

sub start($)
{
    my ($commit_template) = @_;
    commit_start($commit_template);
    rclocal_start();
    deferred_start();
}

sub end()
{
    commit_end();
    rclocal_end();
    deferred_end();
}

# --------------- Commit --------------

1;